package com.infore.siteManagement.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.google.common.collect.Maps;
import com.infore.siteManagement.constant.Constants;
import com.infore.siteManagement.constant.ResultConstants;
import com.infore.siteManagement.dto.AreaDto;
import com.infore.siteManagement.entity.Area;
import com.infore.siteManagement.entity.AreaLevel;
import com.infore.siteManagement.enums.ResultStatus;
import com.infore.siteManagement.repository.IAreaLevelRespository;
import com.infore.siteManagement.repository.IAreaRespository;
import com.infore.siteManagement.select.QueryDispatcher;
import com.infore.siteManagement.select.dto.QueryParamDto;
import com.infore.siteManagement.select.util.QueryUtil;
import com.infore.siteManagement.service.IAreaService;
import com.infore.siteManagement.util.AreaDiguiUtil;
import com.infore.siteManagement.util.AreaTreeUtil;
import com.infore.siteManagement.util.MyBeanUtils;
import com.infore.siteManagement.util.Page;
import com.infore.siteManagement.util.PageUtil;
import com.infore.siteManagement.util.ResultEntity;
import com.infore.siteManagement.vo.AreaNameVo;
import com.infore.siteManagement.vo.AreaTreeVo;
/**
 * 区域管理服务实现类
 * @author 刘乐法
 *
 *
 */
@Service
public class IAreaServiceImpl implements IAreaService{

	@Autowired
	private IAreaRespository iAreaRespository;
	@Autowired
	private QueryDispatcher queryDispatcher;
	@Autowired
	private IAreaLevelRespository iAreaLevelRespository;
	
	public ResultEntity queryArea(QueryParamDto queryParamDto) {
		if (org.springframework.util.StringUtils.isEmpty(queryParamDto)) {//无任何条件查询
			List<Area> list = iAreaRespository.findAll();
			return new ResultEntity(ResultStatus.SUCCESS,Constants.QUERY_SUCCESS).setDataList(list);
		//仅分页查询
		}else if (!org.springframework.util.StringUtils.isEmpty(queryParamDto.getPageObject()) && 
				org.springframework.util.StringUtils.isEmpty(queryParamDto.getQueryCondition()) &&
				org.springframework.util.StringUtils.isEmpty(queryParamDto.getAssembleCondition()) && 
				org.springframework.util.StringUtils.isEmpty(queryParamDto.getAssembleSql())) {
			org.springframework.data.domain.Page<Area> pageable = iAreaRespository.findAll(queryParamDto.getPageObject().getPageRequest());
			Page<Area> page = PageUtil.pageConvert(pageable);
			return new ResultEntity(ResultStatus.SUCCESS,Constants.QUERY_SUCCESS).setPage(page);
		//只传属性不传字段的查询
		}else if (org.apache.commons.lang.StringUtils.isBlank(queryParamDto.getAssembleSql().getSelect())) {
			return this.queryAll(queryParamDto);
		}
		//指定字段查询
		return queryDispatcher.dispatcher(queryParamDto, Area.class);
	}
	
	@SuppressWarnings("serial")
	public ResultEntity queryAll(QueryParamDto queryParamDto) {
		//判断是否有条件再判断是否需要分页,不分页必须传null
		if (!org.springframework.util.StringUtils.isEmpty(queryParamDto.getPageObject())) {
			//需要分页
			org.springframework.data.domain.Page<Area> pageAble =  iAreaRespository.findAll(new Specification<Area>() {
				public Predicate toPredicate(Root<Area> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
					//构建条件
					List<Predicate> predicates = com.infore.siteManagement.select.util.QueryUtil.
							createQueryCondition(queryParamDto, criteriaBuilder, root);
					//组装条件
					Predicate predicate = com.infore.siteManagement.select.util.QueryUtil.
							assembleCondition(queryParamDto, criteriaBuilder, predicates);
					QueryUtil.assembleSql(queryParamDto, criteriaBuilder, query, root, predicate);
					return query.getRestriction();
				}
			}, queryParamDto.getPageObject().getPageRequest());
			Page<Area> page = PageUtil.pageConvert(pageAble);
			return new ResultEntity(ResultStatus.SUCCESS,Constants.QUERY_SUCCESS).setPage(page);
		}else {
			List<Area> list = iAreaRespository.findAll(new Specification<Area>() {
				public Predicate toPredicate(Root<Area> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
					//构建条件
					List<Predicate> predicates = com.infore.siteManagement.select.util.QueryUtil.
							createQueryCondition(queryParamDto, criteriaBuilder, root);
					//组装条件
					Predicate predicate = com.infore.siteManagement.select.util.QueryUtil.
							assembleCondition(queryParamDto, criteriaBuilder, predicates);
					QueryUtil.assembleSql(queryParamDto, criteriaBuilder, query, root, predicate);
					return query.getRestriction();
				}
			});
			return new ResultEntity(ResultStatus.SUCCESS,Constants.QUERY_SUCCESS).setDataList(list);
		}
	}

	public ResultEntity deleteArea(String ids) {
		//如果含有“,”，则拆分删除多个
		if (ids.contains(",")) {
			List<String> idsList = Arrays.asList(ids.split(","));
			iAreaRespository.deleteByAreaIdIn(idsList);
		} else {
			iAreaRespository.deleteById(ids);
		}
		return new ResultEntity(ResultStatus.SUCCESS,Constants.DELETE_SUCCESS);
	}

	public ResultEntity editArea(Area area) {
		//如果新增id不可以空
		//falg为false flag用来判断返回的Constants.UPDATE_SUCCESS还是Constants.INSERT_SUCCESS
		Boolean falg = false;
		if (StringUtils.isNotBlank(area.getAreaId())) {
			Area areaOld = iAreaRespository.findById(area.getAreaId()).orElse(null);
			if (org.springframework.util.StringUtils.isEmpty(areaOld)) {
				MyBeanUtils.copyNonNullProperties(area, areaOld);
				area = areaOld;
			}
			falg = true;
		}else {
			return new ResultEntity(ResultStatus.ERROR,ResultConstants.AREA_Id);
		} 
		ResultEntity resultEntity = validateArea(area);
		if (resultEntity.getCode() == 1) {
			return resultEntity;
		}
		try {
			iAreaRespository.saveAndFlush(area);
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (falg) {
			return new ResultEntity(ResultStatus.SUCCESS,Constants.UPDATE_SUCCESS);
		} else {
			return new ResultEntity(ResultStatus.SUCCESS,Constants.INSERT_SUCCESS);
		}
	}

	@Override
	public ResultEntity validateArea(Area area) {
		String message = "验证区域成功";
		if (StringUtils.isEmpty(area.getAreaId())) {
			message = "区域id为空";
		}else if (area.getAreaId().length() > 32) {
			message = "区域id过长";
		}else if (area.getAreaCode().length() > 50) {
			message = "区域编码过长";
		}else if (area.getParentId().length() > 32) {
			message = "父标识过长";
		}else if (area.getAreaName().length() >50) {
			message = "区域名称过长";
		}else if (area.getAreaLevel().getAreaLevelId().length() > 32) {
			message = "区域等级过长";
		}
		if (message.equals("验证区域成功")) {
			return new ResultEntity(ResultStatus.SUCCESS,message);
		}else {
			return new ResultEntity(ResultStatus.ERROR,message);
		}
	}

	public ResultEntity provinceInfo() {
		List<Area> areas = iAreaRespository.findByAreaLevelAreaLevelId("ffbb7faf62044604b7fae55a75303c22");
		List<AreaNameVo> list = new ArrayList<AreaNameVo>();
		for (Area area : areas) {
			AreaNameVo vo = new AreaNameVo();
			vo.setId(area.getAreaId());
			vo.setCode(area.getAreaCode());
			vo.setName(area.getAreaName());
			list.add(vo);
		}
		return new ResultEntity(ResultStatus.SUCCESS,Constants.UPDATE_SUCCESS).setDataList(list);
	}

	public ResultEntity areaInfo(String name) {
		Area areaT = iAreaRespository.findByAreaId(name);
		List<Area> areas = iAreaRespository.findByParentId(areaT.getAreaCode());
		List<AreaNameVo> list = new ArrayList<AreaNameVo>();
		for (Area area : areas) {
			AreaNameVo vo = new AreaNameVo();
			vo.setId(area.getAreaId());
			vo.setCode(area.getAreaCode());
			vo.setName(area.getAreaName());
			list.add(vo);
		}
		return new ResultEntity(ResultStatus.SUCCESS,Constants.UPDATE_SUCCESS).setDataList(list);
	}

	public ResultEntity addOrEdit(AreaDto areaDto) {
		String code = areaDto.getCode() == null?"":areaDto.getCode();
		String name = areaDto.getName() == null?"":areaDto.getName();
		String fatherCode = areaDto.getFatherCode() == null?"":areaDto.getFatherCode();
		String levelId = areaDto.getLevelId() == null?"":areaDto.getLevelId();
		String remark = areaDto.getRemark() == null?"":areaDto.getRemark();
		String areaId = areaDto.getAreaId() == null?"":areaDto.getAreaId();
		String aimWaterLevel = areaDto.getAimWaterLevel() == null?"":areaDto.getAimWaterLevel();
		String sort = areaDto.getSort() == null?"":areaDto.getSort();
		Area area = new Area();
		if (StringUtils.isNotBlank(levelId)) {
			AreaLevel areaLevel = iAreaLevelRespository.findOneByAreaLevelId(levelId);
			if (areaLevel != null) {
				area.setAreaLevel(areaLevel);
			}
		}
		area.setAreaCode(code);
		area.setAreaName(name);
		area.setRemark(remark);
		area.setParentId(fatherCode);
		area.setAimWaterLevel(aimWaterLevel);
		area.setSort(Integer.parseInt(sort));
		//查询是否已经存在
		if (StringUtils.isNotBlank(areaId)) {
			area.setAreaId(areaId);
			Area areaOld = iAreaRespository.findById(areaId).orElse(null);
			if (areaOld != null) {
				MyBeanUtils.copyNonNullProperties(area, areaOld);
				area = areaOld;
			}else {
				return new ResultEntity(ResultStatus.SUCCESS,ResultConstants.NO_SUCH_OBJECT);
			}
		}
		try {
			iAreaRespository.saveAndFlush(area);
		} catch (Exception e) {
			e.printStackTrace();
			return new ResultEntity(ResultStatus.SUCCESS,ResultConstants.AREA_CODE);
		}
		if (StringUtils.isNotBlank(areaId)) {
			return new ResultEntity(ResultStatus.SUCCESS,Constants.UPDATE_SUCCESS);
		}
		return new ResultEntity(ResultStatus.SUCCESS,Constants.INSERT_SUCCESS);
	}

	public ResultEntity areaTree(String name) {
		List<AreaTreeVo> bodyList = new ArrayList<AreaTreeVo>();//保存除根结点（也可包含）其他节点
		List<AreaTreeVo> rootList = new ArrayList<AreaTreeVo>();//保存根节点
//		List<Area> areas = iAreaRespository.findAll(new Specification<Area>() {
//			public Predicate toPredicate(Root<Area> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
//				List<Predicate> predicates = new ArrayList<Predicate>();
//				if (StringUtils.isNotBlank(name)) {
//					predicates.add(criteriaBuilder.like(root.get("areaName"),"%"+name+"%"));
//				}
//				return query.where(predicates.toArray(new Predicate[predicates.size()]))
//						.orderBy(criteriaBuilder.asc(root.get("sort"))).getRestriction();
//			}
//		});
		List<Area> areas = new ArrayList<Area>();
		if (StringUtils.isNotBlank(name)) {
			String areaName = "%"+name+"%";
			areas = iAreaRespository.queryAllByKeyName(areaName);
		}else {
			areas = iAreaRespository.findAll();
		}
		for (Area area : areas) {
			AreaTreeVo areaTreeVo = new AreaTreeVo();
			areaTreeVo.setAimWaterLevel(area.getAimWaterLevel());
			areaTreeVo.setAreaCode(area.getAreaCode());
			areaTreeVo.setAreaId(area.getAreaId());
			areaTreeVo.setAreaLevel(area.getAreaLevel());
			areaTreeVo.setAreaName(area.getAreaName());
			areaTreeVo.setRemark(area.getRemark());
			areaTreeVo.setSort(area.getSort());
			areaTreeVo.setParentId(area.getParentId());
			if (StringUtils.isBlank(area.getParentId())) {
				areaTreeVo.setPid("");
				areaTreeVo.setNodeId(area.getAreaCode());
				rootList.add(areaTreeVo);
			}else {
				//String parentId = area.getParentId() == null ?"":area.getParentId();
				areaTreeVo.setPid(area.getParentId());
				areaTreeVo.setNodeId(area.getAreaCode());
				bodyList.add(areaTreeVo);
			}
		}
		AreaTreeUtil utils = new AreaTreeUtil(rootList,bodyList);
		List<AreaTreeVo> list = utils.getTree(); 
		return new ResultEntity(ResultStatus.SUCCESS,Constants.QUERY_SUCCESS).setDataList(list);
	}

    @Override
    public List<Area> areaParents(String codes) {
        Map<String,String> map = new HashMap<String, String>();
        List<Area> result = new ArrayList<>();
        List<Area> bodyList = iAreaRespository.findAll();
        List<Area> rootList = iAreaRespository.findByAreaCodeIn(Arrays.asList(codes.split(",")));
        AreaDiguiUtil utils = new AreaDiguiUtil(rootList,bodyList);
        List<Area> list = utils.getParents();
        list.addAll(rootList);
        list.stream()
        .filter(c -> !map.containsKey(c.getAreaId()))
        .forEach(c ->{
            map.put(c.getAreaId(),c.getParentId());
            result.add(c);
        });
        return result ;
    }

}
